﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using ComponentFactory.Krypton.Toolkit;
using hf_plat_core;
using Trade2015;
using Quote2015;


namespace hf_plat_terminal
{
	/*
	 * 1.显示成交记录,突出当日委托.
	 * 2.策略中增加"是否下单(为True时策略加入_listorder)"和"启动"字段,
	 * 3.策略中增加"报告"字段
	 * 4.行情源选择
	 * 5.属列表在策略启动后不再允许编辑
	 * 
	 * 加载增加progressbar
	 * 6.行情订阅与策略调用
	 * 7.实盘委托
	 * 8.Tick回测
	 */
	public partial class Plat : UserControl
	{
		private readonly ConcurrentDictionary<string, Strategy> _dicStrategies = new ConcurrentDictionary<string, Strategy>();
		private readonly List<Strategy> _listOrderStra = new List<Strategy>();
		private readonly List<Strategy> _listOnTickStra = new List<Strategy>();

		private readonly Trade _t;
		private readonly Quote _q;
		private readonly DataTable _dtOrders = new DataTable();

		private readonly Timer _timer = new Timer
		{
			Interval = 1000
		};

		private Strategy _curStrategy;
		private readonly ConcurrentDictionary<string, TradeTimeInfo> _tradeTimes = new ConcurrentDictionary<string, TradeTimeInfo>();


		public Plat(Trade pTrade, Quote pQuote)
		{
			_t = pTrade;
			_q = pQuote;
			//取时间过滤
			if (File.Exists("TradingTime.xml"))
			{
				XmlDocument doc = new XmlDocument();
				doc.Load("TradingTime.xml");
				if (doc.DocumentElement != null)
					foreach (XmlNode proc in doc.DocumentElement.ChildNodes)
					{
						var tti = _tradeTimes.GetOrAdd(proc.Name, new TradeTimeInfo());
						foreach (XmlNode sec in proc.ChildNodes)
						{
							TimeSpan start = TimeSpan.Parse(sec.Attributes["start"].InnerText);
							TimeSpan end = TimeSpan.Parse(sec.Attributes["end"].InnerText);

							if (end < start) //隔夜
								end = end.Add(TimeSpan.FromDays(1));

							if (sec.Attributes["state"].InnerText == "open")
								tti.MatchTime = start.Add(TimeSpan.FromMinutes(-1)).ToString();
							else if (sec.Attributes["state"].InnerText == "close")
								tti.CloseTime = end.ToString();

							tti.EndTimes.Add(end.ToString());

							for (TimeSpan ts = start; ts < end; ts = ts.Add(TimeSpan.FromMinutes(1)))
								tti.Times.Add(ts.ToString()); //.ToString(@"hh\:mm\:ss"));
						}
					}
			}
			InitializeComponent();
		}

		private void Plat_Load(object sender, EventArgs e)
		{
			foreach (var file in new DirectoryInfo(".\\strategy\\").GetFiles("*.dll"))
			{
				if (file.Name == "hf_plat_core.dll")
				{
					continue;
				}
				Assembly ass = Assembly.LoadFile(file.FullName);
				//加载hf_plat报错:增加对hf_plat_core的引用
				foreach (var t in ass.GetTypes())
				{
					if (t.BaseType == typeof(Strategy))
						this.kryptonComboBoxType.Items.Add(t);
				}
			}

			KryptonDataGridViewComboBoxColumn col = (KryptonDataGridViewComboBoxColumn)this.kryptonDataGridViewStrategies.Columns["Instrument"];
			//合约列表
			var listInst = _t.DicInstrumentField.Keys.ToList();
			listInst.Sort();
			col.Items.AddRange(listInst.ToArray());

			//时间周期
			col = (KryptonDataGridViewComboBoxColumn)this.kryptonDataGridViewStrategies.Columns["Interval"];
			col.Items.AddRange(new[] { "Sec 1", "Min 1", "Min 3", "Min 5", "Min 10", "Min 15", "Min 30", "Hour 1", "Day 1", "Week 1", "Year 1" });

			//设置表格
			_dtOrders.Columns.Add("ID", typeof(int));//增加编号列
			foreach (PropertyInfo v in typeof(OrderItem).GetProperties())
			{
				//有说明的属性才显示
				if (v.GetCustomAttributes(false).Any())
					_dtOrders.Columns.Add(v.Name, v.PropertyType);
			}
			//_dtOrders.PrimaryKey = new[] { _dtOrders.Columns[""] };
			this.kryptonDataGridViewOrders.DataSource = _dtOrders;

			_q.OnRtnTick += _q_OnRtnTick;


			LoadStrategy();
			_timer.Tick += _timer_Tick;
			_timer.Start();
		}

		void _timer_Tick(object sender, EventArgs e)
		{
			foreach (DataGridViewRow row in this.kryptonDataGridViewStrategies.Rows)
			{
				Strategy stra;
				if (_dicStrategies.TryGetValue((string)row.Cells["StraName"].Value, out stra))
				{
					if (stra.Datas.Count > 0)
					{
						row.Cells["UpdateTime"].Value = string.IsNullOrEmpty(stra.Tick.UpdateTime) ? stra.D[0].ToString() : stra.Tick.UpdateTime.Split(' ')[1];
						ExchangeStatusType status;
						if (_t.DicExcStatus.Count == 1)
							row.Cells["ExcStatus"].Value = _t.DicExcStatus.ElementAt(0).Value;
						else if (_t.DicExcStatus.TryGetValue(stra.InstrumentInfo.ProductID, out status))
							row.Cells["ExcStatus"].Value = status;
					}
				}
			}
		}

		protected override void OnHandleDestroyed(EventArgs e)
		{
			SaveStrategy();
			//解除事件绑定及现场清理
			_timer.Stop();
			_q.OnRtnTick -= _q_OnRtnTick;
			base.OnHandleDestroyed(e);
		}

		void _q_OnRtnTick(object sender, TickEventArgs e)
		{
			string actionDay = _t.TradingDay;
			//大商所夜盘,actionday为第2天日期,即tradingday
			string min = e.Tick.UpdateTime.Substring(0, 6) + "00";
			TradeTimeInfo tti;
			InstrumentField instField;
			if (_t.DicInstrumentField.TryGetValue(e.Tick.InstrumentID, out instField) && _tradeTimes.TryGetValue(instField.ProductID, out tti) || _tradeTimes.TryGetValue("default", out tti))
			{
				int idx = tti.Times.IndexOf("1.00:00:00");
				if (idx >= 0) //有夜盘的品种
				{
					string startDay;
					string tomorrowDay;
					//确定startDay&tomorrowDay
					if (DateTime.Now.TimeOfDay > TimeSpan.Parse(tti.CloseTime))
					{
						startDay = DateTime.Today.ToString("yyyyMMdd");
						tomorrowDay = DateTime.Today.AddDays(1).ToString("yyyyMMdd");
					}
					else
					{
						tomorrowDay = DateTime.Today.ToString("yyyyMMdd");
						startDay = DateTime.Today.AddDays(-1).ToString("yyyyMMdd");
					}

					int minIndex;
					if (
						//正常行情
						(minIndex = tti.Times.IndexOf(min)) >= 0 || (minIndex = tti.Times.IndexOf("1." + min)) >= 0
						//开盘前竞价时间处理
						|| (minIndex = min == tti.MatchTime ? 0 : -1) == 0
						//休息时间(小节&收盘)
						|| (minIndex = tti.EndTimes.IndexOf(min) >= 0 ? tti.Times.IndexOf(TimeSpan.Parse(min).Add(TimeSpan.FromMinutes(-1)).ToString(@"hh\:mm\:ss")) : -1) >= 0
						)
					{
						//处理actionday
						if (minIndex < idx) //
						{
							actionDay = startDay;
							//e.Tick.UpdateTime = _startDay + " " + e.Tick.UpdateTime.Substring(9);
						}
						else //if (tti.Times[minIndex].StartsWith("1."))
						{
							actionDay = tomorrowDay;
							//e.Tick.UpdateTime = _tomorrowDay + " " + e.Tick.UpdateTime.Substring(9);
						}
					}
				}
			}
			e.Tick.UpdateTime = actionDay + " " + e.Tick.UpdateTime;

			var tick = FixTick(e.Tick);
			if (tick == null)
				return;

			foreach (var v in _dicStrategies)
			{
				if (_listOnTickStra.IndexOf(v.Value) >= 0 && v.Value.InstrumentID == tick.InstrumentID)
				{
					v.Value.Datas[0].OnTick(new Tick
					{
						AskPrice = tick.AskPrice,
						AskVolume = tick.AskVolume,
						AveragePrice = tick.AveragePrice,
						BidPrice = tick.BidPrice,
						BidVolume = tick.BidVolume,
						InstrumentID = tick.InstrumentID,
						LastPrice = tick.LastPrice,
						LowerLimitPrice = tick.LowerLimitPrice,
						OpenInterest = tick.OpenInterest,
						UpdateMillisec = tick.UpdateMillisec,
						UpdateTime = tick.UpdateTime,
						UpperLimitPrice = tick.UpperLimitPrice,
						Volume = tick.Volume,
					});
					v.Value.Update();
				}
			}
		}

		private MarketData FixTick(MarketData tick)
		{
			//过滤Tick
			InstrumentField instField;
			if (!_t.DicInstrumentField.TryGetValue(tick.InstrumentID, out instField))
				return null;
			string proc = instField.ProductID;
			string min = tick.UpdateTime.Substring(9, 6) + "00";
			TradeTimeInfo tti;//修改夜盘相关数据时,同时修改数据转换程序
			if (((proc == "au" || proc == "ag") && String.Compare(tick.UpdateTime, "20130708 20:50:00", StringComparison.Ordinal) < 0) //贵金属夜盘
				|| ((proc == "cu" || proc == "al" || proc == "zn" || proc == "pb") && String.Compare(tick.UpdateTime, "20131223 20:50:00", StringComparison.Ordinal) < 0)
				|| ((proc == "p" || proc == "j") && String.Compare(tick.UpdateTime, "20140705 20:50:00", StringComparison.Ordinal) < 0) //大商所夜盘
				|| !_tradeTimes.TryGetValue(proc, out tti))
				_tradeTimes.TryGetValue("default", out tti); //没有对应配置,取默认
			//if (_tradeTimes.TryGetValue(instField.ProductID, out tti) || _tradeTimes.TryGetValue("default", out tti))
			if (tti != null)
			{
				int minIndex = tti.Times.IndexOf(min);
				if (minIndex >= 0 || tti.Times.IndexOf("1." + min) >= 0)
					return tick;
				//开盘前竞价时间处理
				if (min == tti.MatchTime)
				{
					tick.UpdateTime = tick.UpdateTime.Substring(0, 9) + tti.Times[0];
				}
				//休息时间(小节&收盘)
				else if ((minIndex = tti.EndTimes.IndexOf(min)) >= 0)
				{
					tick.UpdateTime = tick.UpdateTime.Substring(0, 9) + TimeSpan.Parse(tti.EndTimes[minIndex]).Add(TimeSpan.FromSeconds(-1)).ToString(@"hh\:mm\:ss");
				}
				else
					return null;
			}
			return tick;
		}

		void SaveStrategy()
		{
			string str = "StraName,Type,Instrument,Interval,BeginDate,EndDate,Param\r\n";
			foreach (DataGridViewRow row in this.kryptonDataGridViewStrategies.Rows)
			{//参数置于最后,避免参数中的','影响加载时分隔
				Strategy stra;
				if (!_dicStrategies.TryGetValue((string)row.Cells["StraName"].Value, out stra))
					continue;
				str += string.Format("{0},{1},{2},{3},{4},{5} ,{6}\r\n", stra.Name, stra.GetType(),
					row.Cells["Instrument"].Value, row.Cells["Interval"].Value,
					row.Cells["BeginDate"].Value, row.Cells["EndDate"].Value, row.Cells["Param"].Value);
			}
			File.WriteAllText("strategies.txt", str);
		}

		void LoadStrategy()
		{
			if (File.Exists("strategies.txt"))
			{
				string[] lines = File.ReadAllLines("strategies.txt");
				for (int i = 1; i < lines.Length; ++i)
				{
					string[] fields = lines[i].Split(new[] { ',' }, 7);
					Type straType = null;
					//类型是否存在
					foreach (Type t in this.kryptonComboBoxType.Items)
					{
						if (t.ToString() == fields[1])
						{
							straType = t;
							break;
						}
					}
					if (straType == null)
						continue;
					Strategy stra = (Strategy)Activator.CreateInstance(straType);
					//参数赋值
					foreach (var v in fields[6].Trim('(', ')').Split(','))
					{
						stra.SetParameterValue(v.Split(':')[0], v.Split(':')[1]);
					}

					int rid = AddStra(stra, fields[0]);
					if (rid == -1)//加载不成功
					{
						continue;
					}
					//按读取数据修正
					this.kryptonDataGridViewStrategies.Rows[rid].Cells["Instrument"].Value = fields[2];
					this.kryptonDataGridViewStrategies.Rows[rid].Cells["Interval"].Value = fields[3];
					this.kryptonDataGridViewStrategies.Rows[rid].Cells["BeginDate"].Value = DateTime.Parse(fields[4]);
					if (!string.IsNullOrWhiteSpace(fields[5]))
					{
						((KryptonDataGridViewDateTimePickerCell)this.kryptonDataGridViewStrategies.Rows[rid].Cells["EndDate"]).Checked = true;
						this.kryptonDataGridViewStrategies.Rows[rid].Cells["EndDate"].Value = DateTime.Parse(fields[5]);
					}
				}
			}
		}

		//添加策略
		void kryptonButtonAdd_Click(object sender, EventArgs e)
		{
			if (string.IsNullOrEmpty(this.kryptonTextBoxName.Text))
			{
				KryptonMessageBox.Show("名称不能为空", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return;
			}
			Strategy stra = (Strategy)Activator.CreateInstance((Type)this.kryptonComboBoxType.SelectedItem);
			AddStra(stra, this.kryptonTextBoxName.Text);
		}

		private int AddStra(Strategy stra, string pName)
		{
			if (!_dicStrategies.TryAdd(pName, stra))
			{
				KryptonMessageBox.Show("名称不能重复", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return -1;
			}
			stra.Name = pName;
			int rid = this.kryptonDataGridViewStrategies.Rows.Add(stra.Name, stra.GetType(), stra.GetParams());
			this.kryptonDataGridViewStrategies.Rows[rid].Cells["Order"].Value = false;
			this.kryptonDataGridViewStrategies.Rows[rid].Cells["BeginDate"].Value = DateTime.Today.AddMonths(-3);

			this.propertyGrid1.SelectedObject = stra;	//属性显示

			stra.OnRtnOrder += stra_OnRtnOrder;
			return rid;
		}

		//改变数据源
		private void kryptonButtonDataSource_Click(object sender, EventArgs e)
		{
			using (FolderBrowserDialog fbd = new FolderBrowserDialog())
			{
				if (fbd.ShowDialog() == DialogResult.OK)
				{
					this.kryptonTextBoxData.Text = fbd.SelectedPath;

				}
			}
		}

		//策略委托:
		void stra_OnRtnOrder(OrderItem pOrderItem, Data pData, Strategy pStrategy)
		{
			//实际委托
			if (_listOrderStra.IndexOf(pStrategy) >= 0)
			{
				//处理上期所平今操作
				InstrumentField instField;
				if (pOrderItem.Offset == Offset.Close)
				{
					int lots = pOrderItem.Lots;
					if (_t.DicInstrumentField.TryGetValue(pData.Instrument, out instField) && instField.ExchangeID == "SHFE")
					{
						PositionField posiField;
						if (_t.DicPositionField.TryGetValue(pData.Instrument + "_" + (pOrderItem.Dir == Direction.Buy ? "Sell" : "Buy"), out posiField))
						{
							if (posiField.TdPosition > 0)
							{
								int lot = Math.Min(posiField.TdPosition, lots);
								_t.ReqOrderInsert(pData.Instrument, pOrderItem.Dir == Direction.Buy ? DirectionType.Buy : DirectionType.Sell, OffsetType.CloseToday, pOrderItem.Price, pOrderItem.Lots, pCustom: pStrategy.Name);
								lots -= lot;
							}
							if (lots > 0)
							{
								_t.ReqOrderInsert(pData.Instrument, pOrderItem.Dir == Direction.Buy ? DirectionType.Buy : DirectionType.Sell, OffsetType.Close, pOrderItem.Price, pOrderItem.Lots, pCustom: pStrategy.Name);
							}
						}
					}
					else
						_t.ReqOrderInsert(pData.Instrument, pOrderItem.Dir == Direction.Buy ? DirectionType.Buy : DirectionType.Sell, OffsetType.Close, pOrderItem.Price, pOrderItem.Lots, pCustom: pStrategy.Name);
				}
				else
					_t.ReqOrderInsert(pData.Instrument, pOrderItem.Dir == Direction.Buy ? DirectionType.Buy : DirectionType.Sell, OffsetType.Open, pOrderItem.Price, pOrderItem.Lots, pCustom: pStrategy.Name);
			}
		}

		//启动策略/报告
		private void kryptonDataGridViewStrategies_CellContentClick(object sender, DataGridViewCellEventArgs e)
		{
			if (e.ColumnIndex < 0 || e.RowIndex < 0)
			{
				return;
			}

			DataGridViewRow row = this.kryptonDataGridViewStrategies.Rows[e.RowIndex];
			string name = (string)row.Cells["StraName"].Value;
			Strategy stra;
			if (_dicStrategies.TryGetValue(name, out stra))
			{
				this.propertyGrid1.SelectedObject = stra;
				string head = this.kryptonDataGridViewStrategies.Columns[e.ColumnIndex].Name;
				if (head == "Start" || head == "TickLoad")
				{
					//判断是否可以启动
					string inst = string.Empty;
					if (string.IsNullOrEmpty(inst = (string)row.Cells["Instrument"].Value))
					{
						KryptonMessageBox.Show("请选择合约!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
						return;
					}
					if (row.Cells["Interval"].Value == null) //周期
					{
						KryptonMessageBox.Show("请选择周期!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
						return;
					}
					if (row.Cells["BeginDate"].Value == null) //开始时间
					{
						KryptonMessageBox.Show("请选择起始日期!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
						return;
					}
					//参数是否可修改
					this.propertyGrid1.Enabled = !this.propertyGrid1.Enabled;
					//加载与tick加载同时处理
					this.kryptonDataGridViewStrategies["Start", e.RowIndex].Value =
					this.kryptonDataGridViewStrategies["TickLoad", e.RowIndex].Value = !this.propertyGrid1.Enabled ? "已加载" : "已停止";
					row.Cells["Instrument"].ReadOnly = row.Cells["BeginDate"].ReadOnly = row.Cells["EndDate"].ReadOnly = row.Cells["Interval"].ReadOnly = !this.propertyGrid1.Enabled;

					if (this.kryptonDataGridViewStrategies[e.ColumnIndex, e.RowIndex].Value.Equals("已加载"))
					{
						string internalType = (string)row.Cells["Interval"].Value;

						Data data = new Data
						{
							Interval = int.Parse(internalType.Split(' ')[1]),
							IntervalType = (EnumIntervalType)Enum.Parse(typeof(EnumIntervalType), internalType.Split(' ')[0]),
							Instrument = inst,
						};

						InstrumentField tmp;
						if (_t.DicInstrumentField.TryGetValue(inst, out tmp) || ((tmp = _t.DicInstrumentField.FirstOrDefault(n => inst.IndexOf(n.Value.ProductID) == 0 && char.IsDigit(inst[n.Value.ProductID.Length])).Value) != null))
						{
							if (data.InstrumentInfo == null)
								data.InstrumentInfo = new InstrumentInfo();
							data.InstrumentInfo.ExchangeID = tmp.ExchangeID;
							data.InstrumentInfo.InstrumentID = inst;
							data.InstrumentInfo.PriceTick = tmp.PriceTick;
							data.InstrumentInfo.ProductID = tmp.ProductID;
							data.InstrumentInfo.VolumeMultiple = tmp.VolumeMultiple;
						}

						DateTime dtBegin = ((DateTime)row.Cells["BeginDate"].Value).Date;
						DateTime dtEnd = ((KryptonDataGridViewDateTimePickerCell)row.Cells["EndDate"]).Checked ? ((DateTime)row.Cells["EndDate"].Value).Date : DateTime.MaxValue;

						_dtOrders.Rows.Clear(); //清除委托列表
						if (data.IntervalType == EnumIntervalType.Sec || head == "TickLoad") //秒周期或tick加载
						{
							stra.Init(data);
							var ticks = ReadTick(inst, dtBegin, dtEnd);
							if (ticks == null)
							{
								//数据读取有误:恢复加载前状态
								this.propertyGrid1.Enabled = !this.propertyGrid1.Enabled;
								//加载与tick加载同时处理
								this.kryptonDataGridViewStrategies["Start", e.RowIndex].Value =
								this.kryptonDataGridViewStrategies["TickLoad", e.RowIndex].Value = !this.propertyGrid1.Enabled ? "已加载" : "已停止";
								row.Cells["Instrument"].ReadOnly = row.Cells["BeginDate"].ReadOnly = row.Cells["EndDate"].ReadOnly = row.Cells["Interval"].ReadOnly = !this.propertyGrid1.Enabled;
								return;		//可改为修正状态
							}
							foreach (MarketData tick in ticks)
							{
								data.OnTick(new Tick
								{
									AskPrice = tick.AskPrice,
									AskVolume = tick.AskVolume,
									AveragePrice = tick.AveragePrice,
									BidPrice = tick.BidPrice,
									BidVolume = tick.BidVolume,
									InstrumentID = tick.InstrumentID,
									LastPrice = tick.LastPrice,
									LowerLimitPrice = tick.LowerLimitPrice,
									OpenInterest = tick.OpenInterest,
									UpdateMillisec = tick.UpdateMillisec,
									UpdateTime = tick.UpdateTime,
									UpperLimitPrice = tick.UpperLimitPrice,
									Volume = tick.Volume,
								});
								stra.Update();
							}
						}
						else
						{
							var bars = ReadData(inst, data.Interval, data.IntervalType, dtBegin, dtEnd);
							if (bars == null)
							{
								//数据读取有误:恢复加载前状态
								this.propertyGrid1.Enabled = !this.propertyGrid1.Enabled;
								//加载与tick加载同时处理
								this.kryptonDataGridViewStrategies["Start", e.RowIndex].Value =
								this.kryptonDataGridViewStrategies["TickLoad", e.RowIndex].Value = !this.propertyGrid1.Enabled ? "已加载" : "已停止";
								row.Cells["Instrument"].ReadOnly = row.Cells["BeginDate"].ReadOnly = row.Cells["EndDate"].ReadOnly = row.Cells["Interval"].ReadOnly = !this.propertyGrid1.Enabled;
								return;
							}
							foreach (Bar bar in bars)
								data.Add(bar); //加入bar
							//=>初始化策略/回测
							stra.Init(data);
						}
						kryptonDataGridViewStrategies_SelectionChanged(null, null); //刷新委托列表
						//是否有结束日期:只测试
						if (dtEnd == DateTime.MaxValue)
						{
							//取当日tick加载:未加载当日数据
							if (stra.D[0] < int.Parse(_t.TradingDay))
							{
								var ticks = ReadTick(inst, DateTime.ParseExact(_t.TradingDay, "yyyyMMdd", null), DateTime.ParseExact(_t.TradingDay, "yyyyMMdd", null));
								foreach (MarketData tick in ticks)
								{
									data.OnTick(new Tick
									{
										AskPrice = tick.AskPrice,
										AskVolume = tick.AskVolume,
										AveragePrice = tick.AveragePrice,
										BidPrice = tick.BidPrice,
										BidVolume = tick.BidVolume,
										InstrumentID = tick.InstrumentID,
										LastPrice = tick.LastPrice,
										LowerLimitPrice = tick.LowerLimitPrice,
										OpenInterest = tick.OpenInterest,
										UpdateMillisec = tick.UpdateMillisec,
										UpdateTime = tick.UpdateTime,
										UpperLimitPrice = tick.UpperLimitPrice,
										Volume = tick.Volume,
									});
									stra.Update();
								}
							}
							_q.ReqSubscribeMarketData(inst);
							_listOnTickStra.Add(stra); //可以接收实际行情
						}
					}
					else
					{
						_listOnTickStra.Remove(stra);
						this.kryptonDataGridViewStrategies["Order", e.RowIndex].Value = false;
						_listOrderStra.Remove(stra);
					}
				}
				else if (head == "Order")
				{
					this.kryptonDataGridViewStrategies.EndEdit();
					if ((bool)(this.kryptonDataGridViewStrategies[e.ColumnIndex, e.RowIndex]).Value)
						_listOrderStra.Add(stra); //可以发送委托
					else
						_listOrderStra.Remove(stra);
				}
				else if (head == "report") //报告
				{
					if (stra.Operations == null || stra.Operations.Count == 0)
						MessageBox.Show("策略无交易");
					else
						new FormTest(stra).Show();
				}
			}
		}

		//读取Tick数据
		public List<MarketData> ReadTick(string pInstrument, DateTime pBegin, DateTime pEnd, bool pReal = false)
		{
			var bars = new List<MarketData>();
			var dataPath = new DirectoryInfo(this.kryptonTextBoxData.Text + "\\Future_Tick\\" + pInstrument);
			if (pReal) //实时tick
				dataPath = new DirectoryInfo(this.kryptonTextBoxData.Text + "\\Future_Real\\" + pInstrument);

			if (!dataPath.Exists)
			{
				MessageBox.Show("无Tick数据源!");
				return null;
			}
			foreach (FileInfo fi in dataPath.GetFiles())// new DirectoryInfo(dataPath.FullName).GetFiles(pInstrument + ".csv", SearchOption.AllDirectories).OrderBy(n => n.DirectoryName))
			{
				if (DateTime.ParseExact(fi.Name.Split('_', '.')[1], "yyyyMMdd", null) < pBegin)
					continue;
				if (DateTime.ParseExact(fi.Name.Split('_', '.')[1], "yyyyMMdd", null) > pEnd)
					break;
				foreach (string line in File.ReadAllLines(fi.FullName))
				{
					if (!char.IsDigit(line[0]))
						continue;
					//#InstrumentID,TradingDay,UpperLimitPrice,LowerLimitPrice,OpenPrice,ClosePrice,SettlementPrice,PreClosePrice,PreOpenInterest,PreSettlementPrice
					//#a1507,20140801,4636,4280,4469,4490,4483,4458,32,4458
					//#LastPrice,BidPrice1,BidVolume1,AskPrice1,AskVolume1,AveragePrice,HighestPrice,LowestPrice,OpenInterest,Turnover,Volume,UpdateTime,UpdateMillisec

					//0.LastPrice,BidPrice1,BidVolume1,AskPrice1,AskVolume1,AveragePrice,HighestPrice,LowestPrice,OpenInterest,
					//9.Turnover,Volume,UpdateTime,UpdateMillisec,ActionDay,TradingDay
					string[] fields = line.Split(',');
					var tick = FixTick(new MarketData
					{
						LastPrice = double.Parse(fields[0]),
						BidPrice = double.Parse(fields[1]),
						BidVolume = int.Parse(fields[2]),
						AskPrice = double.Parse(fields[3]),
						AskVolume = int.Parse(fields[4]),
						AveragePrice = double.Parse(fields[5]),
						OpenInterest = double.Parse(fields[8]),
						Volume = int.Parse(fields[10]),
						UpdateTime = fields[13] + " " + fields[11],
						UpdateMillisec = int.Parse(fields[12]),
						InstrumentID = pInstrument,
						LowerLimitPrice = double.NaN, //.Parse(fields[3]),
						UpperLimitPrice = double.NaN, //(fields[3]),
					});
					if (tick != null)
					{
						bars.Add(tick);
					}
				}
			}
			return bars;
		}

		//读取Kxg数据
		public List<Bar> ReadData(string pInstrument, int pInterval, EnumIntervalType pIntervalType, DateTime pBegin, DateTime pEnd)
		{
			List<Bar> bars = new List<Bar>();
			var dataPath = new DirectoryInfo(this.kryptonTextBoxData.Text + "\\Future_" + (pIntervalType == EnumIntervalType.Day ? "Day" : "Min") + "\\" + pInstrument);
			if (!dataPath.Exists)
			{
				MessageBox.Show("数据源不正确!");
				return null;
			}

			foreach (FileInfo fi in dataPath.GetFiles())// new DirectoryInfo(dataPath.FullName).GetDirectories().GetFiles(pInstrument + "_*.csv", SearchOption.AllDirectories).OrderBy(n => n.DirectoryName))
			{
				if (DateTime.ParseExact(fi.Name.Split('_', '.')[1], "yyyyMMdd", null) < pBegin)
					continue;
				if (DateTime.ParseExact(fi.Name.Split('_', '.')[1], "yyyyMMdd", null) >= pEnd)
					break;
				foreach (string line in File.ReadAllLines(fi.FullName))
				{
					if (!char.IsDigit(line[0]))
						continue;
					//Open,High,Low,Close,Vol,OI,Avg,TickTime,TradingDay
					string[] fields = line.Split(',');
					bars.Add(new Bar
					{
						D = DateTime.Parse(fields[7]),
						O = double.Parse(fields[0]),
						H = double.Parse(fields[1]),
						L = double.Parse(fields[2]),
						C = double.Parse(fields[3]),
						V = double.Parse(fields[4]),
						I = double.Parse(fields[5]),
						A = double.Parse(fields[6]),
					});
				}
				if (pInterval > 1)
				{
					bars = GetUpperPeriod(bars, pInterval, EnumIntervalType.Min);
				}
			}
			return bars;
		}
		private List<Bar> GetUpperPeriod(IList<Bar> datasOfMinute, int pInterval, EnumIntervalType pIntervalType)
		{
			DateTime dtBegin = datasOfMinute[0].D;
			//取首K时间
			switch (pIntervalType)
			{
				case EnumIntervalType.Min:
					dtBegin = dtBegin.Date.AddHours(dtBegin.Hour).AddMinutes(dtBegin.Minute / pInterval * pInterval);
					break;
				case EnumIntervalType.Hour:
					dtBegin = dtBegin.Date.AddHours(dtBegin.Hour / pInterval * pInterval);
					break;
				case EnumIntervalType.Day:
					dtBegin = dtBegin.Date.Date;
					break;
				case EnumIntervalType.Week:
					dtBegin = dtBegin.Date.AddDays(1 - (byte)dtBegin.DayOfWeek);
					break;
				case EnumIntervalType.Month:
					dtBegin = new DateTime(dtBegin.Year, dtBegin.Month, 1);
					break;
				case EnumIntervalType.Year:
					dtBegin = new DateTime(dtBegin.Year, 1, 1);
					break;
				default:
					throw new Exception("参数错误");
			}
			List<Bar> tmp = new List<Bar>();
			Bar item = new Bar
			{
				D = dtBegin,
				O = datasOfMinute[0].O,
				H = datasOfMinute[0].H,
				L = datasOfMinute[0].L,
				C = datasOfMinute[0].C
			};
			//item.Volume = datas[0].Volume;
			//item.Value = datas[0].Value;
			//item.Avg = datas[0].Avg;
			tmp.Add(item);
			DateTime dtNext = DateTime.MinValue;
			switch (pIntervalType)
			{
				case EnumIntervalType.Min:
					dtNext = dtBegin.AddMinutes(pInterval);
					break;
				case EnumIntervalType.Hour:
					dtNext = dtBegin.AddHours(pInterval);
					break;
				case EnumIntervalType.Day:
					dtNext = dtBegin.AddDays(pInterval);
					break;
				case EnumIntervalType.Week:
					dtNext = dtBegin.AddDays(7 * pInterval);
					break;
				case EnumIntervalType.Month:
					dtNext = dtBegin.AddMonths(pInterval);
					break;
				case EnumIntervalType.Year:
					dtNext = dtBegin.AddYears(pInterval);
					break;
			}
			foreach (Bar v in datasOfMinute)
			{
				//在当前K线范围内:更新
				if (v.D >= dtBegin
					&& v.D < dtNext)
				{
					item.H = Math.Max(item.H, v.H);
					item.L = Math.Min(item.L, v.L);
					item.C = v.C;
					item.V += v.V;
					item.I = v.I;
					item.A = v.A;
				}
				else
				{
					//超出当前K线范围
					while (v.D >= dtNext)
					{
						dtBegin = dtNext;
						switch (pIntervalType)
						{
							case EnumIntervalType.Min:
								dtNext = dtBegin.AddMinutes(pInterval);
								break;
							case EnumIntervalType.Hour:
								dtNext = dtBegin.AddHours(pInterval);
								break;
							case EnumIntervalType.Day:
								dtNext = dtBegin.AddDays(pInterval);
								break;
							case EnumIntervalType.Week:
								dtNext = dtBegin.AddDays(7 * pInterval);
								break;
							case EnumIntervalType.Month:
								dtNext = dtBegin.AddMonths(pInterval);
								break;
							case EnumIntervalType.Year:
								dtNext = dtBegin.AddYears(pInterval);
								break;
						}
					}
					item = new Bar
					{
						D = dtBegin,
						O = v.O,
						H = v.H,
						L = v.L,
						C = v.C,
						V = v.V,
						I = v.I,
						A = v.A
					};
					tmp.Add(item);
				}
			}
			return tmp;
		}

		//选择不同策略:显示策略成交记录
		private void kryptonDataGridViewStrategies_SelectionChanged(object sender, EventArgs e)
		{
			SaveStrategy();

			DataGridViewRow row = this.kryptonDataGridViewStrategies.SelectedRows[0];
			this.propertyGrid1.Enabled = (string)row.Cells["TickLoad"].Value != "已加载";
			_dtOrders.Rows.Clear();
			if (_dicStrategies.TryGetValue((string)row.Cells["StraName"].Value, out _curStrategy) && _curStrategy.Datas.Count > 0)
			{
				foreach (var v in _curStrategy.Operations)
				{
					_dtOrders.Rows.Add(_dtOrders.Rows.Count + 1, v.Date, v.Dir, v.Offset, v.Price, v.Lots, v.Remark);
				}
			}
		}

		//策略参数被修改:提交
		private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
		{
			foreach (DataGridViewRow row in this.kryptonDataGridViewStrategies.Rows)
			{
				Strategy stra;
				if (_dicStrategies.TryGetValue((string)row.Cells["StraName"].Value, out stra) && stra.Equals(this.propertyGrid1.SelectedObject))
				{
					row.Cells["Param"].Value = stra.GetParams();
					return;
				}
			}
		}

		private void kryptonDataGridViewStrategies_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
		{
			if (e.ColumnIndex < 0 || e.RowIndex < 0 || e.Value == null) return;

			if (this.kryptonDataGridViewStrategies.Columns[e.ColumnIndex].HeaderText == "时间")
			{
				//e.Value = DateTime.ParseExact(double.Parse((string)e.Value).ToString("00000000.0000"), "yyyyMMdd.HHmm", null).ToString("yyyy/MM/dd HH:mm");
			}
		}
	}
	class TradeTimeInfo
	{
		/// <summary>
		/// 交易时间序列(分钟)
		/// </summary>
		public readonly List<string> Times = new List<string>();
		/// <summary>
		/// 结束时间(小节&收盘)
		/// </summary>
		public readonly List<string> EndTimes = new List<string>();
		/// <summary>
		/// 开盘前竞价时间
		/// </summary>
		public string MatchTime = string.Empty;
		/// <summary>
		/// 收盘时间
		/// </summary>
		public string CloseTime = string.Empty;
	}
}
